{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Use multiple `agents.json` files\n",
    "In this example, we'll show how to use multiple `agents.json` files together to create an agent that posts GIFs to Twitter based on search terms\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install agentsjson\n",
    "%pip install openai"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Setup API keys and references to `agents.json` files\n",
    "Make sure to enable \"Read & Write\" Permissions for Twitter Keys"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "TWITTER_BEARER_TOKEN=\"<your-twitter-bearer-token>\"\n",
    "TWITTER_CONSUMER_KEY=\"<your-twitter-consumer-key>\"\n",
    "TWITTER_CONSUMER_SECRET=\"<your-twitter-consumer-secret>\"\n",
    "TWITTER_ACCESS_TOKEN=\"<your-twitter-access-token>\"\n",
    "TWITTER_ACCESS_TOKEN_SECRET=\"<your-twitter-access-token-secret>\"\n",
    "\n",
    "GIPHY_API_KEY=\"<your-giphy-api-key>\"\n",
    "OPENAI_API_KEY=\"<your-openai-api-key>\"\n",
    "TWITTER_AGENTS_JSON_URL=\"https://raw.githubusercontent.com/wild-card-ai/agents-json/refs/heads/master/agents_json/twitter/agents.json\"\n",
    "GIPHY_AGENTS_JSON_URL=\"https://raw.githubusercontent.com/wild-card-ai/agents-json/refs/heads/master/agents_json/giphy/agents.json\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load the `agents.json` files"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "from agentsjson.core.models import Flow\n",
    "from agentsjson.core.loader import load_agents_json\n",
    "\n",
    "# load the agents.json file\n",
    "twitter_bundle = load_agents_json(TWITTER_AGENTS_JSON_URL)\n",
    "giphy_bundle = load_agents_json(GIPHY_AGENTS_JSON_URL)\n",
    "\n",
    "# get the flows\n",
    "twitter_flows = twitter_bundle.agentsJson.flows\n",
    "giphy_flows = giphy_bundle.agentsJson.flows"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Define agent creation function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "from openai import OpenAI\n",
    "from agentsjson.core import ToolFormat, flows_tools, execute_flows\n",
    "\n",
    "def create_agent(bundle, flows, system_prompt, auth):\n",
    "    openai_client = OpenAI(api_key=OPENAI_API_KEY)\n",
    "    \n",
    "    def agent(user_request):\n",
    "        response = openai_client.chat.completions.create(\n",
    "            model=\"gpt-4o\",\n",
    "            messages=[{\"role\": \"system\", \"content\": system_prompt}, {\"role\": \"user\", \"content\": user_request}],\n",
    "            tools=flows_tools(flows, format=ToolFormat.OPENAI),\n",
    "            tool_choice=\"auto\",\n",
    "        )\n",
    "        \n",
    "        # Run the flows\n",
    "        response = execute_flows(response, format=ToolFormat.OPENAI, bundle=bundle, flows=flows, auth=auth)\n",
    "        return response\n",
    "    return agent"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create Twitter and Giphy agents"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "from agentsjson.core.parsetools import flows_prompt\n",
    "\n",
    "twitter_flows_context = flows_prompt(twitter_flows)\n",
    "giphy_flows_context = flows_prompt(giphy_flows)\n",
    "\n",
    "twitter_system_prompt = f\"\"\"You are an AI assistant that helps users interact with the Twitter API.\n",
    "You have access to the following API flows:\n",
    "\n",
    "{twitter_flows_context}\n",
    "\n",
    "Analyze the user's request and use the appropriate API flows to accomplish the task.\n",
    "You must give your arguments for the tool call as Structued Outputs JSON with keys `parameters` and `requestBody`\"\"\"\n",
    "\n",
    "giphy_system_prompt = f\"\"\"You are an AI assistant that helps users interact with the Giphy API.\n",
    "You have access to the following API flows:\n",
    "\n",
    "{giphy_flows_context}\n",
    "\n",
    "Analyze the user's request and call the corresponding tool call with the appropriate API flows to accomplish the task.\n",
    "You must give your arguments for the tool call as Structued Outputs JSON with keys `parameters` and `requestBody`\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "from agentsjson.core.models.auth import ApiKeyAuthConfig, AuthType, OAuth1AuthConfig\n",
    "\n",
    "twitter_auth = OAuth1AuthConfig(type=AuthType.OAUTH1, consumer_key=TWITTER_CONSUMER_KEY, consumer_secret=TWITTER_CONSUMER_SECRET, access_token=TWITTER_ACCESS_TOKEN, access_token_secret=TWITTER_ACCESS_TOKEN_SECRET)\n",
    "giphy_auth = ApiKeyAuthConfig(type=AuthType.API_KEY, key_value=GIPHY_API_KEY)\n",
    "\n",
    "twitter_agent = create_agent(twitter_bundle, twitter_flows, twitter_system_prompt, twitter_auth)\n",
    "giphy_agent = create_agent(giphy_bundle, giphy_flows, giphy_system_prompt, giphy_auth)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Option 1: Invoke the agents directly"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "giphy_response = giphy_agent(\"find a random cat GIF that is funny\")\n",
    "response = twitter_agent(f\"post a tweet with #agentsjson about a gif we found: {giphy_response}\")\n",
    "\n",
    "response"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Option 2: Create an agent to Orchestrate each Sub-Agent\n",
    "Often a user's request is a single complex task that needs multiple sub-tasks to be accomplished.\n",
    "\n",
    "We can create an agent that orchestrates the sub-agents to accomplish the task.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "\n",
    "agents_list = [\n",
    "    {\n",
    "        \"name\": \"twitter_agent\",\n",
    "        \"agent\": twitter_agent,\n",
    "        \"description\": \"This agent makes requests to the Twitter API.\"\n",
    "    },\n",
    "    {\n",
    "        \"name\": \"giphy_agent\",\n",
    "        \"agent\": giphy_agent,\n",
    "        \"description\": \"This agent makes requests to the Giphy API.\"\n",
    "    }\n",
    "]\n",
    "\n",
    "# Write a prompt for the orchestrator\n",
    "system_prompt = \"\"\"\n",
    "You are a smart AI assistant that can help the user with their requests.\n",
    "Break down the user's request into a list of sub-tasks and determine which agent to use and in what order to accomplish the task.\n",
    "You have access to the following sub-agents with specialized capabilities:\n",
    "\n",
    "{agents_descriptions}\n",
    "\n",
    "Use the appropriate sub-agent tool call to accomplish the task. \n",
    "Make sure to pass a precise natural language description of the task to the sub-agent. Pass the right context from the previous sub-agent's responses to the next sub-agent through the task.\n",
    "\n",
    "You'll be given a response from the previous sub-agent. Use that response to determine the next sub-task and the agent to use.\n",
    "If there's no more sub-tasks to accomplish, return the word STOP.\n",
    "\"\"\"\n",
    "agents_descriptions = \"\\n\".join([f\"- {agent['name']}: {agent['description']}\" for agent in agents_list])\n",
    "formatted_system_prompt = system_prompt.format(agents_descriptions=agents_descriptions)\n",
    "\n",
    "def agents_tools(agents_list):  \n",
    "    return {\n",
    "            \"type\": \"function\",\n",
    "            \"function\": {\n",
    "                \"name\": \"execute_agent\",\n",
    "                \"description\": \"This function is responsible for calling the appropriate agent to accomplish the task.\",\n",
    "                \"parameters\": {\n",
    "                    \"type\": \"object\",\n",
    "                    \"properties\": {\n",
    "                        \"agent_name\": {\n",
    "                            \"type\": \"string\",\n",
    "                            \"enum\": [agent[\"name\"] for agent in agents_list],\n",
    "                            \"description\": \"The name of the agent to call.\"\n",
    "                        },\n",
    "                        \"task\": {\n",
    "                            \"type\": \"string\",\n",
    "                            \"description\": \"The task to accomplish described precisely in natural language.\"\n",
    "                        }\n",
    "                    },\n",
    "                    \"required\": [\"agent_name\", \"task\"],\n",
    "                }\n",
    "            }\n",
    "        }\n",
    "\n",
    "def orchestrator(agents_list, messages):\n",
    "    \n",
    "    print(\"MESSAGES\", messages)\n",
    "        \n",
    "    openai_client = OpenAI(api_key=OPENAI_API_KEY)\n",
    "    \n",
    "    # OpenAI function call to orchestrate the sub-agents\n",
    "    response = openai_client.chat.completions.create(\n",
    "        model=\"gpt-4o\",  # Fixed model name\n",
    "        messages=messages,\n",
    "        tools=[agents_tools(agents_list)],\n",
    "        tool_choice=\"auto\",\n",
    "        parallel_tool_calls=False\n",
    "    )\n",
    "    \n",
    "    # Run all tool calls\n",
    "    responses = []\n",
    "    if not response.choices[0].message.tool_calls:\n",
    "        return \"STOP\"\n",
    "        \n",
    "    for tool_call in response.choices[0].message.tool_calls:\n",
    "        try:\n",
    "            args = json.loads(tool_call.function.arguments)\n",
    "            print(\"ARGS\", args)\n",
    "            task, agent_name = args[\"task\"], args[\"agent_name\"]\n",
    "            \n",
    "            agent = next((a for a in agents_list if a[\"name\"] == agent_name), None)\n",
    "            if agent:\n",
    "                tool_response = agent[\"agent\"](task)\n",
    "                print(\"TOOL_RESPONSE\", tool_response)\n",
    "                responses.append(tool_response)\n",
    "            else:\n",
    "                raise ValueError(f\"Agent {agent_name} not found\")\n",
    "        except json.JSONDecodeError:\n",
    "            raise ValueError(\"Invalid tool call arguments format\")\n",
    "    \n",
    "    # Process the responses\n",
    "    final_response = json.dumps(responses[-1]) if responses else \"STOP\"\n",
    "    if final_response != \"STOP\":\n",
    "        next_responses = orchestrator(agents_list, messages + [{\"role\": \"user\", \"content\": final_response}])\n",
    "        responses.extend(next_responses if isinstance(next_responses, list) else [next_responses])\n",
    "    \n",
    "    return responses"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Run Task"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "query = \"find one random GIF of a cat that is funny and share it on twitter with the hashtag #agentsjson\"\n",
    "\n",
    "orchestrator(agents_list, [{\"role\": \"user\", \"content\": query}])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "liveenv2",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
